/**
 * Copyright (c) 2012 Nokia Corporation. 
 */

package com.nokia.example.tictactoe.connectivity;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.microedition.io.Connector;
import javax.microedition.io.ServerSocketConnection;
import javax.microedition.io.SocketConnection;

/**
 * TCP server.
 */
public class TcpServer extends Connection {
	// Constants
	public static final int BUFFER_SIZE = 255;
	
	// Members
	private ServerSocketConnection _server = null;
	private SocketConnection _connection = null;
	private InputStream _inputStream = null;
	private OutputStream _outputStream = null;
	private Integer _port = null;
	
	/**
	 * Constructor.
	 */
	public TcpServer() {
	}
	
	/**
	 * From Connection.
	 */
	public synchronized boolean open(String hostname, Integer port) {
		if (_state != NOT_CONNECTED) {
			System.out.println("TcpServer::open(): Already open!");
			return false;
		}
		
		setState(CONNECTING);
		_port = port;
		
		try {
			_server = (ServerSocketConnection)Connector.open("socket://:"
						+ _port.toString());
		}
		catch (IOException e) {
			notifyFatalError("TCP server failed to connect: " + e.toString());
			setState(NOT_CONNECTED);
			return false;
		}
		
		System.out.println("TcpServer::open(): Starting to listen on port "
				+ _port.toString());
		
		new Thread() {
			public void run() {
				_running = true;
				
				try {
					// Wait for clients and once one is found, open the
					// connection, I/O streams
					_connection = (SocketConnection)_server.acceptAndOpen();
					_inputStream = _connection.openInputStream();
					_outputStream = _connection.openOutputStream();
					setState(CONNECTED);
				}
				catch (IOException e) {
					if (_running) {
						notifyFatalError("TCP server failed to connect: "
								+ e.toString());
						close();
					}
				}	
				
				// Create the buffer for incoming messages
				byte[] buffer = new byte[BUFFER_SIZE];
				
				while (_running) {
					try {
						_inputStream.read(buffer);
						notifyReceived(buffer);
						
						// Empty the array
						for (int i = 0; i < BUFFER_SIZE; ++i) {
							buffer[i] = 0;
						}
					}
					catch (IOException e) {
						if (_running) {
							notifyFatalError("TCP server failed: " + e.toString());
							close();
						}
					}
				}
				
				buffer = null;
				close();
				setState(NOT_CONNECTED);
			}
		}.start();
		
		return true;
	}

	/**
	 * From Connection.
	 */
	public synchronized boolean send(byte[] message) {
		if (_state == CONNECTED && _outputStream != null) {
			try {
				_outputStream.write(message);
			}
			catch (IOException e) {
				return false;
			}
			
			notifyMessageSent(message);
			return true;
		}
		
		return false;
	}
	
	/**
	 * From Connection.
	 */
	public synchronized void close() {
		System.out.println("TcpServer::close()");
		
		if (_state != NOT_CONNECTED) {
			setState(DISCONNECTING);
		}
		
		_running = false;
		
		if (_inputStream != null) {
			try {
				_inputStream.close();
			}
			catch (IOException e) {}
			
			_inputStream = null;
		}
		
		if (_outputStream != null) {
			try {
				_outputStream.close();
			}
			catch (IOException e) {}
			
			_outputStream = null;
		}
		
		if (_connection != null) {
			try {
				_connection.close();
			}
			catch (IOException e) {}
			
			_connection = null;
		}
		
		if (_server != null) {
			try {
				_server.close();
			}
			catch (IOException e) {}
			
			_server = null;
		}
	}
}
